#include "core/container.h"
#include "core/def.h"

namespace core
{
    StContainer::StContainer() {}

    StContainer::~StContainer() {}

    bool StContainer::IsContainer() { return true; }

    StObject* StContainer::Clone()
    {
        StContainer* container = new StContainer;
        if (!container)
        {
            return 0;
        }

        CopyToWidget(container);
        CopyToContainer(container);

        return container;
    }

    void StContainer::Drop()
    {
        Clear();

        delete this;
    }

    StWidget* StContainer::HitTest(int x, int y)
    {
        return 0;
    }

    bool StContainer::Parse(const XmlElement* element, const StStyleCache& cache)
    {
        if (!element)
        {
            return false;
        }

        if (!StWidget::Parse(element, cache))
        {
            return false;
        }
        return ParseChildren(element, cache);
    }

    void StContainer::LinkBegin(StWidget *add)
    {
        if (!add)
        {
            return;
        }

        add->parent_ = this;

        add->prev_ = 0;
        add->next_ = first_;

        if (first_)
            first_->prev_ = add;
        else
            last_ = add;

        first_ = add;
    }

    void StContainer::LinkEnd(StWidget *add)
    {
        if (!add)
        {
            return;
        }

        add->parent_ = this;

        add->prev_ = last_;
        add->next_ = 0;

        if (last_)
            last_->next_ = add;
        else
            first_ = add;

        last_ = add;
    }

    void StContainer::InsertBefore(StWidget *add, StWidget *before)
    {
        if (add && before && before->parent_ == this)
        {
            add->parent_ = this;

            add->next_ = before;
            add->prev_ = before->prev_;

            if (before->prev_)
            {
                before->prev_->next_ = add;
            }
            else
            {
                first_ = add;
            }

            before->prev_ = add;
        }
    }

    void StContainer::InsertAfter(StWidget *add, StWidget *after)
    {
        if (add && after && after->parent_ == this)
        {
            add->parent_ = this;

            add->next_ = after->next_;
            add->prev_ = after;

            if (after->next_)
            {
                after->next_->prev_ = add;
            }
            else
            {
                last_ = add;
            }

            after->next_ = add;
        }
    }

    void StContainer::Replace(StWidget *with, StWidget *replace)
    {
        if (with && replace && replace->parent_ == this)
        {
            with->parent_ = this;
            with->next_ = replace->next_;
            with->prev_ = replace->prev_;

            if (replace->next_)
                replace->next_->prev_ = with;
            else
                last_ = with;

            if (replace->prev_)
                replace->prev_->next_ = with;
            else
                first_ = with;

            replace->Drop();

            delete replace;
        }
    }

    void StContainer::Remove(StWidget *remove)
    {
        if (remove && remove->parent_ == this)
        {
            if (remove->next_)
                remove->next_->prev_ = remove->prev_;
            else
                last_ = remove->prev_;

            if (remove->prev_)
                remove->prev_->next_ = remove->next_;
            else
                first_ = remove->next_;

            remove->Drop();

            delete remove;
        }
    }

    StWidget* StContainer::FirstChild(const KeyWidget& key)
    {
        for (StWidget* widget = first_; widget != 0; widget = widget->NextSibling())
        {
            if (widget->Key() == key)
                return widget;
        }

        return 0;
    }

    StWidget* StContainer::LastChild(const KeyWidget& key)
    {
        for (StWidget* widget = last_; widget != 0; widget = widget->PreviousSibling())
        {
            if (widget->Key() == key)
                return widget;
        }

        return 0;
    }

    StWidget* StContainer::FindWidget(const KeyWidget& key)
    {
        for (StWidget* widget = first_; widget != 0; widget = widget->NextSibling())
        {
            if (widget->Key() == key)
            {
                return widget;
            }

            if (!widget->IsContainer())
            {
                continue;
            }

            StContainer* container = static_cast<StContainer*>(widget);
            StWidget* find = container->FindWidget(key);
            if (find)
                return find;
        }

        return 0;
    }

    bool StContainer::ParseChildren(const XmlElement *element, const StStyleCache& cache)
    {
        const XmlNode *pNode = 0;
        while (0 != (pNode = element->IterateChildren(pNode)))
        {
            if (!pNode->Value())
            {
                continue;
            }

            if (XmlNode::XML_ELEMENT == pNode->Type())
            {
                const XmlElement * pElement = pNode->ToElement();
                const char * name = pElement->Value();
                StWidget *control = (StWidget *)RuntimeClass::CreateObject(name);
                if (!control)
                {
                    continue;
                }

                control->SetTagName(name);
                control->style_normal_.Inherit(style_normal_);

                LinkEnd(control);
                control->Parse(pElement, cache);
            }
            else if (XmlNode::XML_TEXT == pNode->Type())
            {

            }
        }

        return true;
    }

    void StContainer::CopyToContainer(StContainer* container)
    {
        for (StWidget* widget = first_; widget != 0; widget = widget->NextSibling())
        {
            StObject* obj = widget->Clone();
            if (obj)
                container->LinkEnd(static_cast<StWidget*>(obj));
        }
    }

    void StContainer::Clear()
    {
        StWidget* widget = first_;
        while (widget)
        {
            StWidget* temp = widget->NextSibling();
            widget->Drop();
            widget = temp;
        }
    }

    LRESULT StContainer::OnLayout(WPARAM, LPARAM, bool*)
    {
        return 0;
    }

    LRESULT StContainer::OnPaint(WPARAM, LPARAM, bool*)
    {
        return 0;
    }
}